home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Atari Mega Archive 1
/
Atari Mega Archive - Volume 1.iso
/
language
/
pcl_src.zoo
/
dfun.lsp
< prev
next >
Wrap
Lisp/Scheme
|
1992-07-09
|
34KB
|
904 lines
;;; -*- Mode:LISP; Package:PCL; Base:10; Syntax:Common-Lisp -*-
;;;
;;; *************************************************************************
;;; Copyright (c) 1985, 1986, 1987, 1988, 1989, 1990 Xerox Corporation.
;;; All rights reserved.
;;;
;;; Use and copying of this software and preparation of derivative works
;;; based upon this software are permitted. Any distribution of this
;;; software or derivative works must comply with all applicable United
;;; States export control laws.
;;;
;;; This software is made available AS IS, and Xerox Corporation makes no
;;; warranty about the software, its performance or its conformity to any
;;; specification.
;;;
;;; Any person obtaining a copy of this software is requested to send their
;;; name and post office or electronic mail address to:
;;; CommonLoops Coordinator
;;; Xerox PARC
;;; 3333 Coyote Hill Rd.
;;; Palo Alto, CA 94304
;;; (or send Arpanet mail to CommonLoops-Coordinator.pa@Xerox.arpa)
;;;
;;; Suggestions, comments and requests for improvements are also welcome.
;;; *************************************************************************
;;;
(in-package 'pcl)
#|
This implementation of method lookup was redone in early August of 89.
It has the following properties:
- It's modularity makes it easy to modify the actual caching algorithm.
The caching algorithm is almost completely separated into the files
cache.lisp and dlap.lisp. This file just contains the various uses
of it. There will be more tuning as we get more results from Luis'
measurements of caching behavior.
- The metacircularity issues have been dealt with properly. All of
PCL now grounds out properly. Moreover, it is now possible to have
metaobject classes which are themselves not instances of standard
metaobject classes.
** Modularity of the code **
The actual caching algorithm is isolated in a modest number of functions.
The code which generates cache lookup code is all found in cache.lisp and
dlap.lisp. Certain non-wrapper-caching special cases are in this file.
** Handling the metacircularity **
In CLOS, method lookup is the potential source of infinite metacircular
regress. The metaobject protocol specification gives us wide flexibility
in how to address this problem. PCL uses a technique which handles the
problem not only for the metacircular language described in Chapter 3, but
also for the PCL protocol which includes additional generic functions
which control more aspects of the CLOS implementation.
The source of the metacircular regress can be seen in a number of ways.
One is that the specified method lookup protocol must, as part of doing
the method lookup (or at least the cache miss case), itself call generic
functions. It is easy to see that if the method lookup for a generic
function ends up calling that same generic function there can be trouble.
Fortunately, there is an easy solution at hand. The solution is based on
the restriction that portable code cannot change the class of a specified
metaobject. This restriction implies that for specified generic functions,
the method lookup protocol they follow is fixed.
More precisely, for such specified generic functions, most generic functions
that are called during their own method lookup will not run portable methods.
This allows the implementation to usurp the actual generic function call in
this case. In short, method lookup of a standard generic function, in the
case where the only applicable methods are themselves standard doesn't
have to do any method lookup to implement itself.
And so, we are saved.
|#
;An alist in which each entry is of the form :
; (<generator> . (<subentry> ...))
;Each subentry is of the form:
; (<args> <constructor> <system>)
(defvar *dfun-constructors* ())
;If this is NIL, then the whole mechanism
;for caching dfun constructors is turned
;off. The only time that makes sense is
;when debugging LAP code.
(defvar *enable-dfun-constructor-caching* t)
(defun show-dfun-constructors ()
(format t "~&DFUN constructor caching is ~A."
(if *enable-dfun-constructor-caching*
"enabled" "disabled"))
(dolist (generator-entry *dfun-constructors*)
(dolist (args-entry (cdr generator-entry))
(format t "~&~S ~S"
(cons (car generator-entry) (caar args-entry))
(caddr args-entry)))))
(declaim (ftype (function (T &rest T) real-function) get-dfun-constructor))
(defun get-dfun-constructor (generator &rest args)
(let* ((generator-entry (assq generator *dfun-constructors*))
(args-entry (assoc args (cdr generator-entry) :test #'equal)))
(if (null *enable-dfun-constructor-caching*)
(apply-function (symbol-function generator) args)
(or (cadr args-entry)
(let ((new (apply-function (symbol-function generator) args)))
(if generator-entry
(push (list (copy-list args) new nil) (cdr generator-entry))
(push (list generator (list (copy-list args) new nil)) *dfun-constructors*))
new)))))
(defun load-precompiled-dfun-constructor (generator args system constructor)
(let* ((generator-entry (assq generator *dfun-constructors*))
(args-entry (assoc args (cdr generator-entry) :test #'equal)))
(unless args-entry
(if generator-entry
(push (list args constructor system) (cdr generator-entry))
(push (list generator (list args constructor system)) *dfun-constructors*)))))
(defmacro precompile-dfun-constructors (&optional system)
#+excl (declare (ignore system))
#+excl ()
#-excl
(let ((*precompiling-lap* t))
`(progn
,@(gathering1 (collecting)
(dolist (generator-entry *dfun-constructors*)
(dolist (args-entry (cdr generator-entry))
(when (or (null (caddr args-entry))
(eq (caddr args-entry) system))
(when system (setf (caddr args-entry) system))
(multiple-value-bind (closure-variables arguments
iregs vregs fvregs tregs lap)
(apply-function (symbol-function (car generator-entry))
(car args-entry))
(gather1
(make-top-level-form `(precompile-dfun-constructor
,(car generator-entry))
'(load)
`(load-precompiled-dfun-constructor
',(car generator-entry)
',(car args-entry)
',system
(precompile-lap-closure-generator ,closure-variables
,arguments
,iregs
,vregs
,fvregs
,tregs
,lap))))))))))))
;;;
;;; When all the methods of a generic function are automatically generated
;;; reader or writer methods a number of special optimizations are possible.
;;; These are important because of the large number of generic functions of
;;; this type.
;;;
;;; There are a number of cases:
;;;
;;; ONE-CLASS-ACCESSOR
;;; In this case, the accessor generic function has only been called
;;; with one class of argument. There is no cache vector, the wrapper
;;; of the one class, and the slot index are stored directly as closure
;;; variables of the discriminating function. This case can convert to
;;; either of the next kind.
;;;
;;; TWO-CLASS-ACCESSOR
;;; Like above, but two classes. This is common enough to do specially.
;;; There is no cache vector. The two classes are stored a separate
;;; closure variables.
;;;
;;; ONE-INDEX-ACCESSOR
;;; In this case, the accessor generic function has seen more than one
;;; class of argument, but the index of the slot is the same for all
;;; the classes that have been seen. A cache vector is used to store
;;; the wrappers that have been seen, the slot index is stored directly
;;; as a closure variable of the discriminating function. This case
;;; can convert to the next kind.
;;;
;;; N-N-ACCESSOR
;;; This is the most general case. In this case, the accessor generic
;;; function has seen more than one class of argument and more than one
;;; slot index. A cache vector stores the wrappers